/*
 * Copyright (C) 2011 Nicola Bonzanni
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.vu.few.ibivu.jlemon;

import java.util.Iterator;

import nl.vu.few.ibivu.jlemon.concepts.Arc;
import nl.vu.few.ibivu.jlemon.concepts.Edge;
import nl.vu.few.ibivu.jlemon.concepts.Graph;
import nl.vu.few.ibivu.jlemon.concepts.HasEdges;
import nl.vu.few.ibivu.jlemon.concepts.Node;

public class Graphs {
	public static <N extends Node & Comparable<N>, A extends Arc & Comparable<A>> A findArc(Graph<N, A> graph, N source, N target, A previous) {
		Iterator<A> arcs;
		if (previous == null) {
			arcs = new OutgoingArcIterator<A>(graph, source);
		}
		else {
			arcs = new OutgoingArcIterator<A>(graph, previous);
		}
		while (arcs.hasNext()) {
			A arc = arcs.next();
			if (graph.target(arc).equals(target))
				return arc;
		}
		return null;
	}
	
	public static <N extends Node & Comparable<N>, A extends Arc & Comparable<A>> Iterator<A> connectedArcIterator(final Graph<N, A> graph, final N source, final N target, final A previous) {
		return new Iterator<A>() {

			A next = findArc(graph, source, target, previous);
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			@Override
			public A next() {
				A current = next;
				next = findArc(graph, source, target, current);
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
	
	public static <N extends Node & Comparable<N>, E extends Edge & Comparable<E>> E findEdge(HasEdges<N, E, ?> graph, N u, N v, E previous) {
		Iterator<E> edges;
		if (previous == null) {
			edges = new IncidentEdgeIterator<E>(graph, u);
		}
		else {
			edges = new IncidentEdgeIterator<E>(graph, u, previous);
		}
		while (edges.hasNext()) {
			E edge = edges.next();
			if (graph.v(edge).equals(v))
				return edge;
		}
		return null;
	}
	
	/**
	 * Iterator for iterating on edges connected the same nodes. It is higher level interface for the findEdge() function.
	 * @param <N>
	 * @param <E>
	 * @param graph
	 * @param u
	 * @param v
	 * @param previous
	 * @return
	 */
	public static <N extends Node & Comparable<N>, E extends Edge & Comparable<E>> Iterator<E> connectedEdgeIterator(final HasEdges<N, E, ?> graph, final N u, final N v, final E previous) {
		return new Iterator<E>() {

			E next = findEdge(graph, u, v, previous);
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			@Override
			public E next() {
				E current = next;
				next = findEdge(graph, u, v, current);
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
}
